
package com.joysuch.wwyt;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.List;

import javax.persistence.EntityManager;
import javax.servlet.MultipartConfigElement;

import cn.zlg.common.datasafety.DataCheckConfig;
import cn.zlg.common.datasafety.DataDeleteChecker;
import cn.zlg.common.datasafety.DefaultDataDeleteChecker;
import cn.zlg.common.springmvc.validate.ValidationExceptionResolver;
import com.alibaba.druid.support.http.StatViewServlet;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;
import com.joysuch.wwyt.audit.support.SubRepositoryFactoryBean;
import com.joysuch.wwyt.core.common.security.SHA1CredentialsDigest;
import com.joysuch.wwyt.core.support.EntityAuditorAware;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.querydsl.SimpleEntityPathResolver;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.unit.DataSize;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.servlet.HandlerExceptionResolver;

/**
 * 应用启动的主入口
 */
// @Configuration
// 此三项也未用到，但二次开发时有可能会用到，暂时不屏蔽：JdbcTemplateAutoConfiguration.class, JtaAutoConfiguration.class,
// WebSocketAutoConfiguration.class
// 暂时不用Mobile的自动配置：DeviceResolverAutoConfiguration.class, SitePreferenceAutoConfiguration.class
// @EnableAutoConfiguration(exclude = { MessageSourceAutoConfiguration.class, JmxAutoConfiguration.class,
// CacheAutoConfiguration.class })
@PropertySource({ "classpath:spring.jpa.properties" })
@ImportResource({ "classpath:context*.xml" })
// @ComponentScan({ "com.joysuch.wwyt" })
@ServletComponentScan
@EnableJpaAuditing
@EnableTransactionManagement
@EnableJpaRepositories(repositoryFactoryBeanClass = SubRepositoryFactoryBean.class, basePackages = {
        "com.joysuch.wwyt.**" })
@EnableAspectJAutoProxy
// 开启基于注解的定时任务
// 创建war需要继承SpringBootSerxvletInitializer
// Weblogic要求直接实现WebApplicationInitializer接口，即使SpringBootServletInitializer已经实现了这个接口
@SpringBootApplication(exclude = { org.activiti.spring.boot.SecurityAutoConfiguration.class,
        org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class }, scanBasePackages = {
                "com.joysuch.wwyt.**", "cn.zlg.**" })
public class Application extends org.springframework.boot.web.servlet.support.SpringBootServletInitializer
        implements WebApplicationInitializer {
    /**
     * war方式启动的处理方法
     */
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return configureApplication(builder);
    }

    /**
     * jar方式启动的处理方法
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        configureApplication(new SpringApplicationBuilder()).run(args);
        System.out.println("------------------------------->启动成功");
    }

    /**
     * war方式启动和jar方式启动共用的配置
     *
     * @param builder
     * @return
     */
    private static SpringApplicationBuilder configureApplication(SpringApplicationBuilder builder) {
        return builder.sources(Application.class)
                .listeners(new ApplicationListener<ApplicationEnvironmentPreparedEvent>() {
                    // 在应用环境准备好后执行（Application.properties和PoropertySource已读取），此时BeanFactory还未准备好（Bean还未创建）
                    @Override
                    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
                        ConfigurableEnvironment env = event.getEnvironment();
                    }
                });
    }

    // hibernate validation
    @Bean
    public HandlerExceptionResolver configureHandlerExceptionResolvers() {
        return new ValidationExceptionResolver();
    }

    // 自动维护修改时间、修改人、更新时间、更新人
    @Bean
    public AuditorAware<Long> auditorProvider() {
        return new EntityAuditorAware();
    }

    @Bean
    public JPAQueryFactory jpaQueryFactory(EntityManager em) {
        return new JPAQueryFactory(em);
    }

    @Bean("credentialsDigest")
    public SHA1CredentialsDigest credentialsDigest() {
        return new SHA1CredentialsDigest();
    }

    @Bean
    public EntityPathResolver entityPathResolver() {
        return new SimpleEntityPathResolver(".dsl");
    }

    @Bean
    public DataDeleteChecker<Long> dataDeleteChecker(EntityManager em) {
        DefaultDataDeleteChecker<Long> check = new DefaultDataDeleteChecker<Long>();
        InputStream stream = Application.class.getClassLoader().getResourceAsStream("data-delete-check.json");
        // InputStream stream = Application.class.getClassLoader().getResourceAsStream("data-delete-check.json");
        Gson gson = new Gson();
        try {
            List<DataCheckConfig> list = gson.fromJson(new InputStreamReader(stream, "utf-8"),
                    new TypeToken<List<DataCheckConfig>>() {
                    }.getType());
            check.setCheckConfig(list);
        } catch (JsonSyntaxException e) {
            e.printStackTrace();
        } catch (JsonIOException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        check.setEntityManager(em);
        return check;
    }

    @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        // 单个文件最大
        factory.setMaxFileSize(DataSize.ofMegabytes(1024));
        return factory.createMultipartConfig();
    }

    @Bean
    public ServletRegistrationBean<StatViewServlet> druidStatViewServlet() {
        ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>(new StatViewServlet(),
                "/druid/*");
        // registrationBean.addInitParameter("allow", "127.0.0.1");// IP白名单 (没有配置或者为空，则允许所有访问)
        registrationBean.addInitParameter("deny", "");// IP黑名单 (存在共同时，deny优先于allow)
        registrationBean.addInitParameter("loginUsername", "root");
        registrationBean.addInitParameter("loginPassword", "root123456");
        registrationBean.addInitParameter("resetEnable", "false");
        return registrationBean;
    }
}
